# coding: utf-8
"""
date: 2019/3/15
收集内网的丢包。
"""
import os
import time
import datetime
import re
import threading as thread


f = open('/root/log/ips.txt')
ips = []
for t in f:
    for tt in t.split(','):
        if '\n' not in tt:
            ips.append(tt)


class Ping1:
    """ 实现：1. 对ping丢包写入文件。 """
    def __init__(self):
        time_now = str(datetime.datetime.now()).split('.')[0]
        self._f = open('/root/log/' + time_now + '.log', 'w+')

    def ping(self):
        while 1:
            time_ = str(datetime.datetime.now()).split('.')[0]
            for no, ip in enumerate(ips):
                cmd = 'ping -c 1 -W 1 ' + ip
                print(time_)
                self._f.write(time_ + '\n')
                output = os.popen(cmd)
                for txt in output:
                    t_ = txt.strip()
                    if '' == t_:
                        continue
                    print(t_)
                    self._f.write(t_ + '\n')
                self._f.write('\n')
                print()
            time.sleep(2)


class Ping2:
    """
    实现：
    1. 对ping丢包写入文件。
    2. 按天对保存的文件进行切割。
    """
    def __init__(self):
        self._path = '/root/log/'
        file_name = self._path + self._get_time() + '.log'
        self._file = open(file_name, 'w+')
        self._file.write('*** 不分割文件 ***' * 3 + '\n')
        self._cmd = 'ping -c 1 -W 1 '
        self._split_time = 86400                    # 86400 secend equal 1 day.
        self._lines = []
        self._start = time.time()

    def _split_file(self):
        """ 按每天来分割文本文件，或者按照存储大小来分割。"""
        if time.time() - self._start > self._split_time:
            self._start = time.time()
            file_name = self._path + self._get_time() + '.log'
            self._file.flush()
            self._file.close()
            self._file = open(file_name, 'w+')

    def _get_time(self):
        """ 获取时间，年月日时分秒。"""
        return str(datetime.datetime.now()).split('.')[0]

    def ping(self):
        """ ping给定的ip列表，丢包的数据进行保存。"""
        while 1:
            # self._split_file()          # 相比之前的文本输出，现在的文本输出量不必按天来分割文件。

            time_ = self._get_time()
            for _, ip in enumerate(ips):
                ip_output = os.popen(self._cmd + ip)
                for i, txt in enumerate(ip_output):
                    txt = txt.strip()
                    if txt == '':
                        continue
                    self._lines.append(txt)

                    if i == 3 and '100%' not in txt:    # 不包含丢包特征"100%"的列表将被重置。
                        self._lines = []
                        break

                if self._lines:                         # 输出列表中包含内容的话就写入文本。
                    self._lines.insert(0, time_)
                    for _, txt in enumerate(self._lines):
                        self._file.write(txt + '\n')
                        print(txt)
                    print()
                    self._lines = []                    # 列表全部内容写入文本后清零。
                    self._file.write('\n')
            self._file.flush()                          # 刷新缓冲区，将内存里的内容写入磁盘。
            time.sleep(1)


class Ping3:
    """
    实现：
    1. 对ping丢包写入文件。
    2. 按天或按文件大小对保存的文件进行切割。
    3. 可以选择是否保存文件，留一份数据在内存中。
    问题：
    1. ping使用的是单线程，在ping多个站点存在延迟的时候会导致在固定时间内执行ping的次数降低，
    从而会反应在固定时间内ping的次数偏低。（在Ping4中使用多线程解决这个问题。）
    """
    def __init__(self):
        # self.pings = []
        self._pings = {}
        ping_thread = thread.Thread(target=self._ping)
        ping_thread.start()

    def _get_time(self):
        return datetime.datetime.strptime(str(datetime.datetime.now()).split('.')[0], '%Y-%m-%d %H:%M:%S')

    def _ping(self):
        ips = ['www.python.org', 'www.google.com']
        # ips = ['www.python.org', 'www.google.com', 'www.facebook.com', 'twitter.com']
        while 1:
            for ip in ips:
                ping = os.popen('ping -c 1 -w 1 ' + ip)
                for lose in ping:
                    if '100%' in lose:
                        if ip not in self._pings:
                            self._pings[ip] = [str(self._get_time())]
                            break
                        else:
                            self._pings[ip].append(str(self._get_time()))
                            break
            # print(self.pings)

    def _select(self, time_: str):
        cu_time_ = self._get_time()
        statis_ips = {}
        time_range = 7

        for _ in range(1, time_range + 1):
            if time_ == 'days':
                cu_time_temp = str(cu_time_ - datetime.timedelta(days=_))
                day = cu_time_temp.split(' ')[0]
            elif time_ == 'hours':
                cu_time_temp = str(cu_time_ - datetime.timedelta(hours=_))
                day = cu_time_temp.split(':')[0]
            elif time_ == 'minutes':
                cu_time_temp = str(cu_time_ - datetime.timedelta(minutes=_))
                times = 0
                for c in range(len(cu_time_temp)):
                    if cu_time_temp[c] == ':':
                        times += 1
                        continue
                    if times == 2:
                        times = c
                        break
                day = cu_time_temp[0: times - 1]

            for key in self._pings.keys():
                count = 0
                for value in self._pings[key]:
                    if re.match(day, value):
                        count += 1
                if key not in statis_ips:
                    statis_ips[key] = [(day, count)]
                else:
                    statis_ips[key].append((day, count))
        # print(statis_ips)
        return statis_ips
    pass

    def select(self, time_):
        return self._select(time_)


class Ping4:
    """
    实现：
    1. 用多线程解决ping超时1秒种等待超时不能进行其他ping操作的问题。
    """
    def __init__(self):
        # self.pings = []
        self.pings = {}
        ping_thread = thread.Thread(target=self._ping)
        ping_thread.start()

    def _get_time(self):
        return datetime.datetime.strptime(str(datetime.datetime.now()).split('.')[0], '%Y-%m-%d %H:%M:%S')

    def _ping_wrap_thread(self, ip):
        ping_command = 'ping -c 1 -w 1 ' + ip
        while True:
            ping = os.popen(ping_command)
            for lose in ping:
                if '100%' in lose:
                    if ip not in self.pings:
                        self.pings[ip] = [str(self._get_time())]
                        break
                    else:
                        self.pings[ip].append(str(self._get_time()))
                        break

    def _ping(self):
        # ips = ['www.facebook.org', 'www.google.com', 'www.python.org']
        for ip in ips:
            thread.Thread(target=self._ping_wrap_thread, args=(ip,)).start()

    def _select(self, time_: str):
        cu_time_ = self._get_time()
        statis_ips = {}
        time_range = 7

        for _ in range(1, time_range + 1):
            if time_ == 'days':
                cu_time_temp = str(cu_time_ - datetime.timedelta(days=_))
                match_time = cu_time_temp.split(' ')[0]
            elif time_ == 'hours':
                cu_time_temp = str(cu_time_ - datetime.timedelta(hours=_))
                match_time = cu_time_temp.split(':')[0]
            elif time_ == 'minutes':
                cu_time_temp = str(cu_time_ - datetime.timedelta(minutes=_))
                times = 0
                for c in range(len(cu_time_temp)):
                    if cu_time_temp[c] == ':':
                        times += 1
                        continue
                    if times == 2:
                        times = c
                        break
                match_time = cu_time_temp[0: times - 1]

            for key in self.pings.keys():
                count = 0
                for value in self.pings[key]:
                    if re.match(match_time, value):
                        count += 1
                if key not in statis_ips:
                    statis_ips[key] = [(match_time, count)]
                else:
                    statis_ips[key].append((match_time, count))
        print(self.pings)
        print(time_ , ' >>> ', statis_ips)
        return statis_ips
    pass

    def select(self, time_):
        return self._select(time_)


class Ping5:
    """
    实现：
    1. 用多线程解决ping超时1秒种等待超时不能进行其他ping操作的问题。
    """
    def __init__(self):
        self.pings = {}
        ping_thread = thread.Thread(target=self._ping)
        ping_thread.start()

    def _get_time(self):
        return datetime.datetime.strptime(str(datetime.datetime.now()).split('.')[0], '%Y-%m-%d %H:%M:%S')

    def _pack_ping_thread(self, ip):
        ping_command = 'ping -c 1 -w 1 ' + ip
        while True:
            ping = os.popen(ping_command)
            for lose in ping:
                if '100%' in lose:
                    if ip not in self.pings:
                        self.pings[ip] = [str(self._get_time())]
                        break
                    else:
                        self.pings[ip].append(str(self._get_time()))
                        break

    def _ping(self):
        # ips = ['www.facebook.org', 'www.google.com', 'www.python.org']
        for _ in ips:
            thread.Thread(target=self._pack_ping_thread, args=(_,)).start()

    def _select(self, time_: str):
        cu_time_ = self._get_time()
        statis_ips = {}
        save_time = ''
        time_range = 7

        for _ in range(time_range):
            if time_ == 'days':
                cu_time_temp = str(cu_time_ - datetime.timedelta(days=_))
                match_time = cu_time_temp[:10]
                save_time = match_time[5:10]
            elif time_ == 'hours':
                cu_time_temp = str(cu_time_ - datetime.timedelta(hours=_))
                match_time = cu_time_temp[:13]
                save_time = match_time[11:13]
            elif time_ == 'minutes':
                cu_time_temp = str(cu_time_ - datetime.timedelta(minutes=_))
                match_time = cu_time_temp[:16]
                save_time = match_time[14:16]
            print('match time : ', match_time)
            print('save time : ', save_time)

            for ip in self.pings.keys():
                count = 0
                for lose_time in self.pings[ip]:
                    if re.match(match_time, lose_time):
                        count += 1

                if ip not in statis_ips:
                    statis_ips[ip] = [(save_time, count)]
                else:
                    statis_ips[ip].append((save_time, count))
        return statis_ips
    pass

    def select(self, time_):
        return self._select(time_)


if __name__ == '__main__':
    p = Ping5()
    while 1:
        p.select('hours')
        time.sleep(1)